package com.fly.swagger

import io.swagger.annotations.ApiOperation
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import springfox.documentation.builders.ApiInfoBuilder
import springfox.documentation.builders.PathSelectors
import springfox.documentation.builders.PathSelectors.regex
import springfox.documentation.builders.RequestHandlerSelectors
import springfox.documentation.service.*
import springfox.documentation.spi.DocumentationType
import springfox.documentation.spi.service.contexts.SecurityContext
import springfox.documentation.spring.web.SpringfoxWebFluxConfiguration
import springfox.documentation.spring.web.plugins.Docket
import springfox.documentation.swagger2.annotations.EnableSwagger2WebFlux


/**
 * @author  fly
 * @date  2021/5/19 14:40
 * @version 1.0
 */
@Configuration
@ConditionalOnProperty(value = ["fly.swagger.enable"], matchIfMissing = true)
@EnableConfigurationProperties(SwaggerProperties::class, IgnoredUrlsProperties::class)
@EnableSwagger2WebFlux
@ConditionalOnClass(SpringfoxWebFluxConfiguration::class)
open class SwaggerConfiguration(
    private val swaggerProperties: SwaggerProperties,
    private val ignoredUrlsProperties: IgnoredUrlsProperties
    ) {

    @Bean
    open fun createRestApi(): Docket = Docket(DocumentationType.SWAGGER_2)
        .groupName(swaggerProperties.group)
        .apiInfo(apiInfo())
        .select()
        .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation::class.java))
        .paths(regex(".*/app/.*").negate())
        .build()
        .securitySchemes(listOf(ApiKey("Authorization", "accessToken", "header")))
        .securityContexts(securityContexts())

    private fun apiInfo(): ApiInfo = ApiInfoBuilder()
        .title(swaggerProperties.title)
        .description(swaggerProperties.description)
        .termsOfServiceUrl(swaggerProperties.termsOfServiceUrl)
        .contact(Contact(swaggerProperties.name, swaggerProperties.url, swaggerProperties.mail))
        .version(swaggerProperties.version)
        .build()


    private fun securityContexts(): List<SecurityContext?> {

        var paths = PathSelectors.ant("")
        for (url in ignoredUrlsProperties.urls) {
            paths = paths.or(PathSelectors.ant(url))
        }
        return listOf(
            SecurityContext.builder()
                .securityReferences(
                    listOf(
                        SecurityReference(
                            "Authorization", arrayOf(
                                AuthorizationScope("global", "")
                            )
                        )
                    )
                )
                .forPaths(paths.negate())
                .build()
        )
    }

}